﻿using System;
using System.Data.Entity.Database;
using System.Linq;
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NpCrm.DataAccess.Repositories;

namespace NpCrm.Domain.Tests
{
    [TestClass]
    public class OrganizationRepositoryTests
    {
        private TransactionScope _scope;
        [TestInitialize]
        public void TestSetup()
        {
            DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<NpCrm.DataAccess.Core.NpCrmDataContext>());
            _scope = new TransactionScope(TransactionScopeOption.RequiresNew,
                                          new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted });
        }

        [TestCleanup]
        public void TestTeardown()
        {
            if (_scope != null)
                _scope.Dispose();
        }

        [TestMethod]
        public void CanAdd()
        {
            AddFakeOrganization();
        }

        [TestMethod]
        public void CanGetById()
        {
            var fakeOrg = AddFakeOrganization();
            using (var orgRepo = new OrganizationRepository())
            {
                var persistedOrg = orgRepo.GetById(fakeOrg.OrganizationId);
                Assert.IsNotNull(persistedOrg);
                Assert.AreNotSame(fakeOrg, persistedOrg);
                CompareOrganizations(fakeOrg, persistedOrg);
            }
        }

        [TestMethod]
        public void CanUpdate()
        {
            var fakeOrg = AddFakeOrganization();
            Organization updateOrg;
            using (var orgRepo = new OrganizationRepository())
            {
                updateOrg = orgRepo.GetById(fakeOrg.OrganizationId);
                updateOrg.Name = "Small Charity";
                updateOrg.TaxIdNumber = "98-7654321";
                updateOrg.UpdateDate = DateTime.Now;
                updateOrg.UpdateUserId = "dlarson";
                orgRepo.Commit();
            }
            using (var orgRepo = new OrganizationRepository())
            {
                var updatedOrg = orgRepo.GetById(updateOrg.OrganizationId);
                Assert.IsNotNull(updatedOrg);
                Assert.AreNotSame(updateOrg, updatedOrg);
                CompareOrganizations(updateOrg, updatedOrg);
            }
        }

        [TestMethod]
        public void CanDelete()
        {
            var fakeOrg = AddFakeOrganization();
            using (var orgRepo = new OrganizationRepository())
            {
                var orgToDelete = orgRepo.GetById(fakeOrg.OrganizationId);
                orgRepo.Delete(orgToDelete);
                orgRepo.Commit();
            }
            using (var orgRepo = new OrganizationRepository())
            {
                var shouldBeNull = orgRepo.GetById(fakeOrg.OrganizationId);
                Assert.IsNull(shouldBeNull);
            }
        }

        public static Organization AddFakeOrganization()
        {
            using (var orgRepo = new OrganizationRepository())
            {
                var fakeOrg = GetFakeOrganization();
                orgRepo.Add(fakeOrg);
                orgRepo.Commit();
                Assert.IsTrue(fakeOrg.OrganizationId > 0);
                return fakeOrg;
            }
        }

        public static Organization GetFakeOrganization()
        {
            return new Organization
                       {
                           CreateDate = DateTime.Now,
                           CreateUserId = "ajohnson",
                           Name = "Huge Corp",
                           TaxIdNumber = "12-3456789"
                       };
        }

        public static void CompareOrganizations(Organization expected, Organization actual)
        {
            Assert.AreEqual(expected.OrganizationId, actual.OrganizationId);
            Assert.AreEqual(expected.Name, actual.Name);
            Assert.AreEqual(expected.TaxIdNumber, actual.TaxIdNumber);
            Assert.AreEqual(expected.CreateUserId, actual.CreateUserId);
            Assert.AreEqual(expected.UpdateUserId, actual.UpdateUserId);
        }
    }
}
